home *** CD-ROM | disk | FTP | other *** search
Java Source | 1999-10-10 | 30.1 KB | 924 lines |
- /****************************************************************************************/
- /** J.Anders * Germany * TU-Chemnitz-Zwickau */
- /****************************************************************************************/
- /** Fakultaet fuer Informatik * Professur "Rechnernetze und */
- /** * verteilte Systeme" */
- /****************************************************************************************/
- /** Telefon: +49 0371 531 1360 * Fax: +49 371 531 1628 */
- /****************************************************************************************/
- /* */
- /* This file contains the whole source code for a FLI/FLC file player in JAVA. */
- /* Parameters: */
- /* FILENAME: URL of the FLI/FLC file (relative or absolut) */
- /* DELAY (optional): delay (in ms) between 2 frames */
- /* during animation (default: 200) */
- /* INDIVDELAY (optional): "y" sets use of individual frame delay values */
- /* (default: don┤t use) */
- /* (see below) */
- /* */
- /* The FLI/FLC player works in 3 steps: */
- /* 1. Loading and parsing of the FLI/FLC file; */
- /* 2. Reconstruction of the single frames; */
- /* 3. Playing of the animation in a thread; */
- /* */
- /****************************************************************************************/
- /* Individual frame delay capability has been added as follows: */
- /* bytes 8 and 9 of each FLIC-frameheader now define (short) delay value for */
- /* this specific frame. */
- /* If the applet┤s parameter INDIVDELAY is set to "y", these individual delay values */
- /* will be used! */
- /* Jan Zimmermann (jan@cosmigo.com; jzi@informatik.tu-chemnitz.de) */
- /* The animation software "Pro Motion" supports this special delay format and */
- /* is available at http://www.cosmigo.com/promotion */
- /*+++++++++++++++++++++++++++ library modules ++++++++++++++++++++++++++++++++++++++++++*/
-
- import java.io.*;
- import java.net.*;
- import java.applet.Applet;
- import java.awt.*;
- import java.awt.image.IndexColorModel;
- import java.awt.image.ColorModel;
- import java.awt.image.ImageProducer;
- import java.awt.image.ImageConsumer;
-
- /*++++++++++++++++++++++++++ auxiliary classes containing data ++++++++++++++++++++++++++*/
-
- class Err
- { // contains a possible error message;
- public static String Msg = null;
- }
-
- class Pixel_List
- { // to build a list of frame data
- public Pixel_List next = null; // (one element per frame)
- public byte color_values[];
- public IndexColorModel curr_Model; // the current color model
-
- Pixel_List (Pixel_List predecessor, IndexColorModel m, int width, int height)
- {
- color_values = new byte[width * height];
- if (m != null)
- { // new color model ?
- curr_Model = m; // adopt
- }
-
- if (predecessor != null)
- {
- // If a predecessor frame is available its data are copied. That's because in general the
- // FLI/FLC file contains a sequence of differences in respect of the predecessor frame.
-
- System.arraycopy(predecessor.color_values, 0, color_values, 0, color_values.length);
-
- // If no new color model is specified the color model of the predecessor frame is used:
-
- if (m == null) curr_Model = predecessor.curr_Model;
- predecessor.next = this;
- }
- }
-
- }
-
- /*++++++++++++++++++++++++++++++++++++++ classes +++++++++++++++++++++++++++++++++++++++*/
-
- /* The class "Flic_Player" implements the applet. It produces an object "scan" of the */
- /* class "Scanner" and passes the FLC/FLI data to it. After that the variables: */
- /* scan.frame_counter */
- /* scan.width */
- /* scan.height */
- /* are set according to the FLI/FLI file data and the variable "scan.anchor" points to */
- /* a list of frame data. */
-
- public class Flic_Player extends Applet implements Runnable
- {
- private int curr_nr = 0; // current frame (during animation)
- private Scanner scan; // THE scanner
- private Thread AnimatorThread; // the animation runs as thread
-
- boolean painted = false; // "true", if the frame "curr_nr" is painted
- boolean loaded = false; // "true", if the frame "curr_nr" is painted
- private int delay = 200; // delay between 2 frames (in ms)
- private int use_indiv_delay=0; // "1" marks use of individual frame delays
- private Image Images[]; // the sequence of images
- private boolean io = true; // "false" in case of errors
- private Image LoadImage;
-
- public void init ()
- {
- // overwrites the method "init()" of Applet
- String filename = null; // THE Name of the FLI/FLC file
- String s_delay = null; // delay (as string)
- String s_indivdelay = null ; // String for param. INDIVDELAY
- URL source_url; // THE source (as URL)
- Pixel_List pl; // auxiliary variable to trace the list of images
- DataInputStream in_stream = null; // THE input stream
-
- this.setBackground(new Color(128,128,128));
-
- try
- {
- // obtain parameters
- filename = getParameter("FILENAME");
- s_delay = getParameter("DELAY");
- s_indivdelay = getParameter("INDIVDELAY");
- if (s_delay != null)
- {
- try
- {
- delay = Integer.parseInt(s_delay);
- }
- catch (NumberFormatException e)
- {
- Err.Msg = s_delay + " is not a number";
- io = false;
- }
- }
-
- if (s_indivdelay != null)
- if (s_indivdelay.toLowerCase().compareTo("y")==0)
- use_indiv_delay=1; // check if indiv. delays shall be used
- }
-
- catch (NullPointerException e)
- {
- Err.Msg = "no parameter \"FILENAME\"";
- io = false;
- }
-
- if (filename == null)
- {
- Err.Msg = "no parameter \"FILENAME\"";
- io = false;
- }
-
- if (io)
- {
- try
- { // construct URL and open the input stream:
- source_url = new URL(getCodeBase(), filename);
- in_stream = new DataInputStream(source_url.openStream());
- }
- catch (MalformedURLException e)
- {
- Err.Msg = "MalformedURLException";
- io = false;
- }
- catch (IOException e)
- {
- Err.Msg = "Cannot open: " + getCodeBase() + "/" + filename;
- io = false;
- }
- }
-
- if (io)
- {
- scan = new Scanner(in_stream); // produce the scanner and pass
- io = scan.scan_flic(); // the input stream to it
- if (io)
- {
- resize(scan.width, scan.height); // but now possible because of
- Images = new Image[scan.frame_counter]; // "frame_counter"
- pl = scan.anchor; // trace the list
- for (int i = 0; i < scan.frame_counter && io; i++)
- {
- if (pl == null)
- {
- // bad "frame_counter" ?
- Err.Msg = "error in tracing the list";
- io = false;
- }
- /*+++ produce one image per frame +++*/
- LoadImage= createImage( new myProducer(pl.color_values,
- scan.width, scan.height, pl.curr_Model));
- Images[i] = this.createImage(scan.width,scan.height);
- Images[i].getGraphics().drawImage(LoadImage,0,0,this);
- LoadImage= null;
- if (use_indiv_delay==0)
- scan.delays[i]=delay; // if not indiv. frame delay capable then use global delay
- pl = pl.next; // continue
- }
- }
- }
-
- loaded=true;
- }
-
- /*+++ The animation must be performed as thread because the +++*/
- /*+++ web browser expects that the "start()" method returns +++*/
- /*+++ after finite time. An infinite animation loop would +++*/
- /*+++ violate against this principle. +++*/
-
- public void run()
- {
- while(true)
- if (loaded)
- {
- long starttime = System.currentTimeMillis(); // notice the start time
- painted = false;
- repaint();
-
- try
- {
- // "sleep()" throws the "InterruptedException"
- starttime += scan.delays[curr_nr % scan.frame_counter]; // compute the destination time
-
- // if destination time isn't reached --> sleep
- Thread.sleep(Math.max(0,starttime - System.currentTimeMillis()));
- }
- catch (InterruptedException e) { }
-
- if (painted) curr_nr++ ;
- }
- else
- try { Thread.sleep(500); } catch (InterruptedException e) { };
- }
-
- /*+++ It is guaranteed that "start()" is called after "init()". +++*/
- /*+++ That means the image sequence list (anchor) already exists. +++*/
- /*+++ The "start()" method leaves behind only a runnable thread +++*/
- /*+++ and returns. +++*/
-
- public void start()
- {
- // overwrites the "start()" method of the Applet
- if (!io) return;
- if (AnimatorThread == null)
- {
- // make sure there is no animation
- AnimatorThread = new Thread(this); // produce the thread
- AnimatorThread.start(); // pass the thread to the scheduler
- }
- }
-
- /*+++ The "update()" method is called at the first opportunity +++*/
- /*+++ after "repaint()" has set the "Please repaint!" - Flag. +++*/
-
- public void update(Graphics g)
- {
- // overwrites the "update()" - method of Applet
- paint(g);
- }
-
- // "stop()" overwrites the "stop()" method of the Applet
-
- public void stop()
- {
- // is called if the page is unloaded
- AnimatorThread = null; // IMPORTANT: otherwise the animation continues in background !!!
- }
-
- /*+++ "paint()" is actually called after "update()" has cleared the +++*/
- /*+++ screen. Because "update()" is overwritten "paint()" is only called +++*/
- /*+++ at the beginning and in case of exposure events. At this +++*/
- /*+++ opportunity a possible error message is displayed. +++*/
-
- public void paint(Graphics g)
- {
- // overwrites the "paint()" method of the Applet
- if (Err.Msg != null)
- {
- g.setFont(new Font(g.getFont().getName(), Font.BOLD, 10));
- g.drawString(Err.Msg, 10, 100);
- return;
- }
- g.drawImage(Images[curr_nr % scan.frame_counter], 0, 0, this);
- painted=true;
- }
- }
-
- /*+++ The class "Scanner" provides the methods suitable to parse the FLI/FLC +++*/
- /*+++ coded data. As a result of calling "scan_flic" the following (public) +++*/
- /*+++ variables are set accordingly to the values in FLI/FLC file: +++*/
- /*+++ +++*/
- /*+++ frame_counter number of frames +++*/
- /*+++ width width of one frame +++*/
- /*+++ height height of one frame +++*/
- /*+++ +++*/
- /*+++ Furthermore the variable "anchor" points to the beginning of a list of +++*/
- /*+++ image data. Each image is stored as a sequence of pixel indexes in +++*/
- /*+++ left-right/top-down manner. The indexes refer to an index color model +++*/
- /*+++ which is stored in this list, too. +++*/
-
- class Scanner
- {
- /*+++ FLI/FLC constants: +++*/
-
- final private int FLI_MAGIC = 0xAF11;
- final private int HEADER_LENGTH = 26 + 102;
- final private int FRAME_HEADER_LENGTH = 16;
- final private short M_FLI = (short) 0xAF11;
- final private short M_FLC = (short) 0xAF12;
- final private short FLI_COLOR_256 = (short) 4;
- final private short FLI_COLOR = (short) 11;
- final private short FLI_LC = (short) 12;
- final private short FLI_WORD_LC = (short) 7;
- final private short FLI_BLACK = (short) 13;
- final private short FLI_BRUN = (short) 15;
- final private short FLI_COPY = (short) 16;
- final private short FRAME_ID = (short) 0xf1fa;
-
- /*+++ public variables (will be set reasonably): +++*/
-
- public Pixel_List anchor = null;
- public int width, height, frame_counter = 0;
- public int delays[];
-
- /*+++ private variables: +++*/
-
- private boolean io = true; // "false" if syntax error
- private byte buffer[]; // portion of source data
- private DataInputStream In_str; // THE input stream
- private Pixel_List last = null; // end of the list of image data
- private IndexColorModel myModel; // "null" if no new color model specified
- private byte r[] = new byte[256]; // sequence of red values in index color model
- private byte g[] = new byte[256]; // sequence of green values in index color model
- private byte b[] = new byte[256]; // sequence of blue values in index color model
- private boolean frame_created = false; // indicates if memory for current frame has been created
-
- Scanner(DataInputStream f_In_str)
- {
- In_str = f_In_str; // notice the input stream
- }
-
- /* The method "scan_fli()" reads the content of the FLI/FLC-header. */
- /* It sets the variables "width" and "height". */
- /* The return value is true if no parsing error occurs. */
-
- public boolean scan_flic()
- {
- int length; // length of file
- short magic, size, speed;
-
- // read the whole header (fix length) to the"buffer":
-
- buffer = new byte[HEADER_LENGTH];
- try
- {
- ReadContent(In_str, buffer, HEADER_LENGTH);
- }
- catch (IOException e)
- {
- Err.Msg = "read error 1";
- return false;
- }
-
- // extract content:
-
- length = to_int(buffer, 4, 0);
- magic = (short) to_int(buffer, 2, 4);
- size = (short) to_int(buffer, 2, 6); // specifies number of frames in flic
- width = (short) to_int(buffer, 2, 8);
- height = (short) to_int(buffer, 2, 10);
- speed = (short) to_int(buffer, 2, 16);
-
- delays = new int[size+1]; // create memory for individual frame delay value (+1 dummy for loop frame)
-
- switch (magic)
- { // OK ?
- case M_FLI: break;
- case M_FLC: break;
- default: Err.Msg = "Number " + magic + "unknown";
- return false;
- }
-
- length -= HEADER_LENGTH; // remaining length
- // The frame count isn't specified in the header. That's why
- // the end of file must be computed by means of file length.
- // Such the frame count is computed implicitely.
-
- while ((length > 0) && io)
- {
- length -= scan_frame();
- // The "frames_counter" cannot be incremented here
- // because a frame not necessarily contains a an image
- // but only a color model.
- }
-
- frame_counter--; // erase the loop frame
-
- return io;
- }
-
- /* The method "scan_frame()" reads data of one frame. A frame */
- /* contains a number of chunks. Such a chunk contains either */
- /* pixel data (FLI_BRUN), pixel difference data (FLI_LC in FLI or */
- /* FLI_WORD_LC in FLC) or a color map (FLI_COLOR in FLI or */
- /* FLI_COLOR_256 in FLC). FLI_COPY, FLI_BLACK and FLI_PREVIEW data */
- /* are ignored and I hope they will never occur. */
- /* The return value is the amount of data in bytes. The method */
- /* changes possibly the value of "io". */
-
- private int scan_frame()
- {
- int frame_size;
- short fh_id, chunks;
-
- // read the whole frame header (fix length) to the"buffer":
-
- buffer = new byte[FRAME_HEADER_LENGTH];
- try
- {
- ReadContent(In_str, buffer, FRAME_HEADER_LENGTH);
- }
- catch (IOException e)
- {
- Err.Msg = "read error 2";
- io = false; return 0;
- }
-
- // extract data:
-
- frame_size = to_int(buffer, 4, 0);
- fh_id = (short) to_int(buffer, 2, 4); // tag
- chunks = (short) to_int(buffer, 2, 6); // count of chunks
- delays[frame_counter] = (short) to_int(buffer, 2, 8); // individual delay for this frame
-
- // First the color model is set to "null". If an FLI_COLOR(_256)
- // appears "myModel" is changed accordingly.
-
- myModel = null;
- frame_created=false;
-
- if (fh_id != FRAME_ID)
- { // check !
- Err.Msg = "FLI/FLC synchronization error";
- io = false; return 0;
- }
-
- for (int ch = 0; ch < chunks; ch++)
- {
- // read the chunk data
- scan_chunk();
- }
-
- return frame_size;
- }
-
- /* The method "scan_chunk()" reads one chunk. Depending on the chunk */
- /* type further methods are called. */
-
- private void scan_chunk()
- {
- int ch_size;
- short ch_type;
-
- // read the chunk header (fix length) to the "buffer":
-
- buffer = new byte[6];
- try
- {
- ReadContent(In_str, buffer, 6);
- }
- catch (IOException e)
- {
- Err.Msg = "read error 3";
- io = false; return;
- }
-
- // extract data:
-
- ch_size = to_int(buffer, 4, 0);
- ch_type = (short) to_int(buffer, 2, 4);
-
- // read the remaining data to the "buffer":
-
- buffer = new byte[ch_size - 6];
- try
- {
- ReadContent(In_str, buffer, ch_size - 6);
- }
- catch (IOException e)
- {
- Err.Msg = "read error 4";
- io = false; return;
- }
- switch (ch_type)
- {
- // dectect chunk type
- case FLI_COLOR: scan_FLI_COLOR(2);break;
- case FLI_COLOR_256: scan_FLI_COLOR(0);break;
- case FLI_LC: scan_FLI_LC(); break;
- case FLI_WORD_LC: scan_FLI_WORD_LC(); break;
- case FLI_BRUN: scan_FLI_BRUN(); break;
- case FLI_BLACK: break;
- case FLI_COPY: break;
- case 0x12: break; // skip postage stamp chunk
- default: Err.Msg = "chunk type " + ch_type + " unknown";
- io = false; return;
- }
- }
-
- /* The method "scan_FLI_BRUN()" reads FLI_BRUN data. These data des- */
- /* cribe an image pixel by pixel. The data are possibly subdivided into */
- /* packets. In the case of a sequence of equal pixel values only the */
- /* pixels value and the length of the sequence is given. */
- /* It is assumed that the FLI_BRUN data are given first. Otherwise the */
- /* player will fail. */
-
- private void scan_FLI_BRUN()
- {
- int idx = 0; // offset in data buffer
- int ppx; // offset in frame
- int pkts; // count of packets in a line
- int xchpx; // current pixel value
- int pixel; // pixel counter
- int line; // current line
- byte f; // to remember a pixel value
-
- short line_count = (short) height;
-
- if (frame_counter > 0)
- {
- // see above !
- Err.Msg = "FLI_BRUN although frame_counter > 0"; io = false; return;
- }
-
- if (myModel == null)
- {
- // no color model ???
- Err.Msg = "No color model for the first frame ?"; io = false; return;
- }
-
- // produce the first element in the list of frames:
-
- last = anchor = new Pixel_List(null, myModel, width, height);
- frame_counter++;
- frame_created=true;
-
- idx = 0;
-
- for (line = 0; line < line_count; line++)
- {
- pkts = (0xff & buffer[idx++]);
- ppx = line * width;
- for (int pkt_nr = 0; pkt_nr < pkts; pkt_nr++)
- {
- xchpx = (int) buffer[idx++];
- if (xchpx >= 0)
- { // set the following byte "xchpx" times
- f = (byte) (0xff & buffer[idx++]);
- for (int k = 0; k < xchpx; k++)
- {
- anchor.color_values[ppx++] = f;
- }
- }
- else
- { // the following "xchpx" bytes are pixel values
- xchpx = -xchpx;
-
- for (pixel = 0; pixel < xchpx; pixel++)
- {
- anchor.color_values[ppx++ ] = (byte)(0xff & buffer[idx++]);
- }
- }
- }
- }
- }
-
-
-
- /* The method "scan_FLI_LC()" recognizes FLI_LC data which occur in FLI */
- /* files. They describe the differences in respect of the predecessor */
- /* frame. After a possible skip of (unchanged) data at the beginning */
- /* follow the data of "line_count" lines. The data of every line are */
- /* possibly subdivided into packets with (possibly) some unchanged */
- /* pixels between them. */
- /* It is assumed that FLI_LC data never occur first. Otherwise the */
- /* player will fail. */
-
- private void scan_FLI_LC()
- {
- int idx = 0; // offset in buffer
- int ppx; // offset in frame
- int pkts; // count of data packets in a line
- int xchpx; // current value
- int pixel; // pixel counter
- int line; // current line
- short line_count; // count of lines to change (after a possbile skipping)
- byte f; // ro remember a pixel value
-
- idx = 0;
- if (frame_counter == 0)
- { // see above !
- Err.Msg = "FLI_LC although frame_counter == 0"; io = false; return;
- }
-
- // produce the next element in the list of frames:
- // (The constructor copies the data of the predecessor
- // frame "last")
-
- /* last.next = new Pixel_List(last, myModel, width, height);
- frame_counter++;
- last = last.next; // update */
-
- if (!frame_created) // create new frame if it does not exist, except first frame
- {
- last.next = new Pixel_List(last, myModel, width, height);
- frame_counter++;
- last = last.next; // update
- frame_created=true;
- }
-
- line = to_int(buffer, 2, idx); idx += 2;
- line_count = (short) to_int(buffer, 2, idx); idx += 2;
-
- for (; line < line_count; line++)
- {
- pkts = (0xff & buffer[idx++]);
- ppx = line * width;
- for (int pkt_nr = 0; pkt_nr < pkts; pkt_nr++)
- {
- ppx += (0xff & buffer[idx++]); // skip pixels
- xchpx = (int) buffer[idx++];
- if (xchpx < 0)
- { // set the following value "xchpx" times
- xchpx = -xchpx;
- f = (byte) (0xff & buffer[idx++]);
- for (int k = 0; k < xchpx; k++)
- {
- last.color_values[ppx++] = f;
- }
- }
- else
- { // the following "xchpx" bytes are pixel values
- for (pixel = 0; pixel < xchpx; pixel++)
- {
- last.color_values[ppx++ ] =
- (byte)(0xff & buffer[idx++]);
- }
- }
- }
- }
- }
-
- /* The method "scan_FLI_WORD_LC()" recognizes FLI_WORD_LC data which */
- /* occur in FLC files. These are pixel difference values in respect of */
- /* the predecessor frame. The pixel values of "line_count" consecutive */
- /* lines are specified followed by a (possible) skip of (unchanged) */
- /* lines. The pixel values are given in double bytes. In the case of an */
- /* odd number of pixels per line the remaining pixel is given in a */
- /* special manner. */
- /* It is assumed that FLI_WORD_LC data never occur first. Otherwise the */
- /* player will fail. */
-
- private void scan_FLI_WORD_LC()
- {
- int idx = 0; // offset in buffer
- int ppx; // offset in frame
- int xchpx; // current value
- int pixel; // pixel counter
- int line; // line counter
- int yoff; // the real current line
- short line_count; // count of lines to change
- short pkts; // count of packets per line
- byte f1, f2; // ro remember 2 pixel values
- boolean last_pix_flag = false; // is a last single pixel stored ?
- byte last_pixel = 0; // value of a last single pixel
-
- idx = 0;
- if (frame_counter == 0)
- { // see above!
- Err.Msg = "FLI_LC_WORD although frame_counter == 0"; io = false; return;
- }
-
- // produce the next element in the list of frames:
- // (The constructor copies the data of the predecessor
- // frame "last")
-
- /* last.next = new Pixel_List(last, myModel, width, height);
- frame_counter++;
- last = last.next; // update */
- if (!frame_created) // create new frame if it does not exist
- {
- last.next = new Pixel_List(last, myModel, width, height);
- frame_counter++;
- last = last.next; // update
- frame_created=true;
- }
-
- line_count = (short) to_int(buffer, 2, idx); idx += 2;
- yoff = 0;
- for (line = 0; line < line_count; line++)
- {
- pkts = (short) to_int(buffer, 2, idx); idx += 2;
- while ((pkts & 0x8000) != 0)
- {
- if ((pkts & 0x4000) != 0)
- { // no packet counter but ...
- yoff -=(int) pkts; // ...count of lines to skip
- }
- else
- { // ...value of a last single pixel
- last_pix_flag = true; // notice!
- last_pixel = (byte) (pkts & 0xff);
- }
- // the packet count follows
- pkts = (short) to_int(buffer, 2, idx); idx += 2;
- }
-
- ppx = yoff * width;
- for (int pkt_nr = 0; pkt_nr < pkts; pkt_nr++)
- {
- ppx += (0xff & buffer[idx++]); // skip pixels
- xchpx = (int) buffer[idx++];
- if (xchpx < 0)
- { // set the following 2 bytes "xchpx" times
- xchpx = -xchpx;
- f1 = (byte) (0xff & buffer[idx++]);
- f2 = (byte) (0xff & buffer[idx++]);
- for (int k = 0; k < xchpx; k++)
- {
- last.color_values[ppx++] = f1;
- last.color_values[ppx++] = f2;
- }
- }
- else
- { // "xchpx" double bytes follow
- for (pixel = 0; pixel < xchpx; pixel++)
- {
- last.color_values[ppx++ ] =
- (byte)(0xff & buffer[idx++]);
- last.color_values[ppx++ ] =
- (byte)(0xff & buffer[idx++]);
- }
- }
- }
-
- if (last_pix_flag)
- { // is there a value of a last single pixel ?
- last.color_values[(yoff + 1) * width - 1] = last_pixel;
- last_pix_flag = false;
- }
-
- yoff++; // count the lines
- }
- }
-
- /* The method "scan_FLI_COLOR(int shift)" recognizes FLI_COLOR data as */
- /* well as FLI_COLOR_256 data. The latter occur in FLC files, the other */
- /* in FLI files. The data describe a color map with 256 color values */
- /* maximal. The difference is: The RGB values in FLI_COLOR_256 are 8 */
- /* bit values; the RGB values in FLI_COLOR are 6 bit values. That means */
- /* the FLI_COLOR data must be "shift"-ed 2 bytes to the left. The */
- /* FLI_COLOR(_256) data are (eventually) subdivided into packets and are*/
- /* (possibly) differences in respect of the predecessor color map. */
- /* Therefore a skipping is possible. Since the arrays "r", "g" and "b" */
- /* are private global variables it is guaranteed that the new values */
- /* are always built in recpect to the existing one. */
- /* The method produces a new color model "myModel". */
-
- private void scan_FLI_COLOR(int shift)
- {
- short pkts; // count of packets
- int skip; // count of values to skip
- int count; // count of values in a packet
- int idx = 0; // offset in buffer
- int table_idx = 0; // index in color map
- pkts = (short) to_int(buffer, 2, 0); idx += 2;
- for (int pkt_nr = 0; pkt_nr < pkts; pkt_nr++)
- {
- skip = 0xff & (buffer[idx++]);
- count= 0xff & (buffer[idx++]);
- table_idx += skip;
- if (count == 0) count = 256; // zero means 256 !!!
- for (int j = 0; j < count; j++)
- { // read RGB values
- r[table_idx ] = (byte) ((0xff & buffer[idx++]) << shift);
- g[table_idx ] = (byte) ((0xff & buffer[idx++]) << shift);
- b[table_idx++] = (byte) ((0xff & buffer[idx++]) << shift);
- }
- }
-
- // After reading the RGB values a new index color model is produced:
-
- myModel = new IndexColorModel(8, 256, r, g, b);
- if ((!frame_created)&&(anchor!=null)) // create new frame if it does not exist, except first frame
- {
- last.next = new Pixel_List(last, myModel, width, height);
- last = last.next; // update
- frame_counter++;
- frame_created=true;
- }
- }
-
-
- /* The method "ReadContent (DataInputStream Stream, byte field[], int size)" */
- /* reads from "Stream" into the "field" until "size" bytes are read or a read */
- /* error occurs. */
-
- private void ReadContent (DataInputStream Stream, byte field[], int size)
- throws IOException
- {
- int bytes_read = 0;
- while (bytes_read < size)
- {
- bytes_read += Stream.read(field, bytes_read, size - bytes_read);
- }
- }
-
- /* Because JAVA has no pointers and no unsigned types a special method */
- /* "int to_int(byte b[], int length, int off)" */
- /* is necessary which reads "length" Bytes at position "off" from "b" and */
- /* translates it to a "length" byte integer value. */
-
- private int to_int(byte b[], int length, int off)
- {
- int r_val = 0;
- for (int i = 0; i < length; i++)
- {
- r_val <<= 8;
- r_val |= b[length - 1 - i + off] & 0xff;
- }
- return r_val;
- }
- }
-
-
- /*+++ JAVA offers 2 possibilities to create an image: +++*/
- /*+++ +++*/
- /*+++ 1. createImage(int width, int height); +++*/
- /*+++ 2. createImage(ImageProducer producer); +++*/
- /*+++ +++*/
- /*+++ The first method isn't suitable here because it requires to draw the +++*/
- /*+++ pixel values by means of a sequence of "draw...()" methods into the image.+++*/
- /*+++ Since all the pixel values and the index color model are known the images +++*/
- /*+++ are produced according to the second method by means of objects of the +++*/
- /*+++ class "myProducer" which implements the interface "ImageProducer". +++*/
- /*+++ An image producer is an object which supplies the pixel values on demand +++*/
- /*+++ of an image consumer. The pixel values are delivered in recpect of a +++*/
- /*+++ certain color model which must be known to the image consumer, too. +++*/
- /*+++ Therefore the image producer must also supply the color model on demand. +++*/
-
- class myProducer implements ImageProducer
- {
- private byte Pix_Data[]; // THE pixel values
- private int width, height; // THE dimensionens
- ColorModel Model; // THE color model
-
- // The constructor only assures that the image producer
- // notices the pixel values, the dimension and the
- // color model.
-
- myProducer(byte pixels[], int w, int h, ColorModel cm)
- {
- Pix_Data = pixels; // Notice that this is a kind of
- // "pointer assignement"! Is is
- // possible because the constructor of
- // "Pixel_List" copies the pixel values.
- width = w; height = h; Model = cm;
- }
-
- // Before the first use the image consumer registers itself
- // to the image producer.
- // At this opportunity he is informed of the dimension and
- // the color model.
-
- public void addConsumer(ImageConsumer ic)
- {
- ic.setDimensions(width, height);
- ic.setColorModel(Model);
- }
-
- public boolean isConsumer(ImageConsumer ic)
- {
- return true; // dummy
- }
-
- public void removeConsumer(ImageConsumer ic)
- {
- // dummy
- }
-
- // The following 2 methods are almost identically.
- // They are called by the image consumer to get the
- // pixel data:
-
- public void requestTopDownLeftRightResend(ImageConsumer ic)
- {
- // Tell the image consumer that the pixel data
- // will be supplied from left to right und from
- // top to bottom:
-
- ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT);
-
- // Send all the pixel data:
-
- ic.setPixels(0, 0, width, height, Model, Pix_Data, 0, width);
-
- // Tell the image consumer that no further data follow:
-
- ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
- }
-
- // The method "startProduction(ImageConsumer ic)" is called by
- // the image consumer if it produces the image.
- // For security it is informed of the color model
- // and the dimensions (I don't know if this is really nenecessary).
-
- public void startProduction(ImageConsumer ic)
- {
- ic.setDimensions(width, height);
- ic.setColorModel(Model);
- requestTopDownLeftRightResend(ic);
- }
- }
-